#include "Handler.h"
#include "Common.h"
#include <assert.h>
#include "pb_base.pb.h"

namespace wsbus {

	void ResponseHandler::onHandle(const PackagePtr &package)
	{
		ResponseHandler::Info info;
		if (pick(package->header().msgId, info)) {
			if (package->command() == "ProtoBase.CommonRsp") {
				auto msg = package->getMessage();
				auto commonRsp = static_cast<ProtoBase::CommonRsp*>(msg.get());
				info.responseCallback(commonRsp->code(), package);
			}
			else {
				info.responseCallback(0, package);
			}
		}
		else {
			LOG(WARNING) << __FUNCTION__ << ", pick not found:" << package->header().msgId << std::endl;
		}
	}

	void ResponseHandler::put(const PackagePtr &msg, const HandleMessage &cb, int msTimeout)
	{
		std::lock_guard<std::mutex> lock(mutex_);
		Info info;
		info.requestMessage = msg;
		info.responseCallback = cb;
		info.msTimeout = msTimeout;
		info.requestTime = currentMillisecond();
		cache_[msg->header().msgId] = info;
	}

	bool ResponseHandler::pick(int msgid, ResponseHandler::Info &info)
	{
		std::lock_guard<std::mutex> lock(mutex_);
		auto it = cache_.find(msgid);
		if (it != cache_.end()) {
			info = it->second;
			info.responseTime = currentMillisecond();
			cache_.erase(it);
			return true;
		}
		return false;
	}

	RequestHandler::RequestHandler(const ReplyMessage &reply) : reply_(reply)
	{

	}

	void RequestHandler::onHandle(const PackagePtr &msg)
	{
		auto it = data_.find(msg->command());
		if (it != data_.end()) {
			auto rspMsg = it->second(msg);
			if (reply_ && rspMsg) {
				reply_(msg, rspMsg);
			}
			else {
				LOG(WARNING) << "onHandle error, command:" << msg->command();
			}
		}
		else {
			LOG(WARNING) << __FUNCTION__ << ", command not found:" << msg->command();
		}
	}

	void RequestHandler::addHandle(const std::string &cmd, const std::function<MoreMessagePtr(const PackagePtr&)> &cb)
	{
		data_[cmd] = cb;
	}


	void PublishHandler::onHandle(const PackagePtr &msg)
	{
		auto it = data_.find(msg->command());
		if (it != data_.end()) {
			it->second(msg);
		}
	}

	void PublishHandler::addHandle(const std::string &cmd, const std::function<void(const PackagePtr)> &cb)
	{
		data_[cmd] = cb;
	}

	std::vector<std::string> PublishHandler::cmdList() const
	{
		std::vector<std::string> result;
		auto it = data_.cbegin();
		while (it != data_.cend()) {
			result.emplace_back(it->first);
			++it;
		}
		return result;
	}

}
